// ==UserScript==
// @name ChatGPT撑开页面宽度
// @namespace https://greasyfork.org/
// @version 1.1.9
// @description 将页面宽度展开
// @author Await
// @match https://chat.openai.com/
// @match https://chat.openai.com/c/*
// @match https://chat.openai.com/?*
// @license MIT
// ==/UserScript==
(function () {
"use strict";
const newMaxWidth = "90rem";
const targetClassName = ".xl\\:max-w-3xl";
const targetClass = "flex flex-col text-sm dark:bg-gray-800";
const desiredMinWidth = 1280;
const styleId = "await-max-width";
const btnId = "await-btn";
// const btnSvgId = "await-svg";
const btnShowTipId = "await-show-tip";
const textClass = "await-text";
const cacheKey = "await-cache";
const cacheOpenStateKey = "await-cache-open-state";
const cacheCloseStateKey = "await-cache-close-state";
const attributeKey = "await-attribute";
const bodyClass = "antialiased";
const maxCount = 10;
// const gptTextareaId = "prompt-textarea";
const growClass = "grow";
function setCache(key, value) {
localStorage.setItem(key, value);
}
function getCache(key) {
return localStorage.getItem(key);
}
function getByClass(className) {
const func = function (name) {
return document.getElementsByClassName(name);
};
return gets(func, className);
}
function getQuery(name) {
const func = function (name) {
return document.querySelector(name);
};
return gets(func, name);
}
function getById(id) {
const func = function (id) {
return document.getElementById(id);
};
return gets(func, id);
}
function gets(fun, name, count = 0) {
const btn = fun(name);
if (!btn) {
if (count > maxCount) {
return null; //防止死循环
}
setTimeout(function () {
return gets(fun, name, count + 1);
}, 1000);
}
return btn;
}
function styleCreate() {
const style = document.createElement("style");
style.innerHTML = `
.${styleId} {
max-width: ${newMaxWidth} !important;
}
// .${btnId}{
// right:2.8rem;
// background-color:transparent !important;
// }
// .${textClass}{
// }
`;
document.head.appendChild(style);
}
function bodyClassFunc() {
const body = getByClass(bodyClass)[0];
if (!body) {
return;
}
const observer = new MutationObserver((mutationsList, observer) => {
for (const mutation of mutationsList) {
if (
mutation.type === "attributes" &&
mutation.attributeName === "style"
) {
const newStyle = body.getAttribute("style");
if (!newStyle) {
btnClickAdd(true);
btnClick(true);
}
}
}
});
const config = { attributes: true, attributeFilter: ["style"] };
observer.observe(body, config);
}
function btnClickAdd(tt = false) {
//只包含这个growClass的class的元素
const promptTextarea = getQuery(`.${growClass}:not([class*=' '])`);
if (!promptTextarea) {
if (!tt) {
return;
} else {
setTimeout(function () {
btnClickAdd(tt);
}, 1000);
return;
}
}
if (!promptTextarea.hasAttribute(attributeKey)) {
promptTextarea.insertAdjacentHTML(
"afterend",
// `
`
``
// ``
);
const cache2 = getCache(cacheKey);
if (cache2 === cacheOpenStateKey) {
openSvg();
} else {
closeSvg();
}
run();
promptTextarea.setAttribute(attributeKey, true);
} else {
if (tt) {
setTimeout(function () {
btnClickAdd(tt);
}, 1000);
}
}
}
function removeStyle(el) {
el.style.transition = "max-width 1s";
setTimeout(function () {
el.style.transition = "";
}, 1000);
el.classList.remove(styleId);
}
function editStyle(el) {
el.style.transition = "max-width 1s";
setTimeout(function () {
el.style.transition = "";
}, 1000);
el.classList.add(styleId);
}
function openSvg() {
const btn = getById(btnId);
//替换btn的svg
btn.innerHTML = "";
btn.insertAdjacentHTML(
"afterbegin",
`还原`
// `撑开`
);
const create = getById(`${btnId}-open`);
setCache(cacheKey, cacheOpenStateKey);
if (!create.hasAttribute(attributeKey)) {
create.addEventListener("click", function () {
closeSvg();
run();
});
create.setAttribute(attributeKey, true);
}
}
function closeSvg() {
const btn = getById(btnId);
btn.innerHTML = "";
btn.insertAdjacentHTML(
"afterbegin",
`撑开`
);
setCache(cacheKey, cacheCloseStateKey);
const create = getById(`${btnId}-open`);
if (!create.hasAttribute(attributeKey)) {
create.addEventListener("click", function () {
openSvg();
run();
});
create.setAttribute(attributeKey, true);
}
}
function checkCache() {
const cache = getCache(cacheKey);
if (!cache) {
setCache(cacheKey, true);
}
}
function setStyle(cache, el) {
if (cache === cacheOpenStateKey) {
editStyle(el);
} else {
removeStyle(el);
}
}
function getNav(count = 0) {
const nav = document.querySelector("nav");
if (!nav) {
if (count > maxCount) {
return null;
}
setTimeout(function () {
return getNav(count);
}, 1000);
}
return nav;
}
function showTip() {
const toggleButton = getNav();
if (!toggleButton) {
return;
}
toggleButton.insertAdjacentHTML(
"beforeend",
`如果页面宽度未展开,请重新点击此树结构导航栏
或者直接点击我
提示内容十秒后自动消失
`
);
const btn = getById(btnShowTipId);
if (!btn.hasAttribute(attributeKey)) {
btn.addEventListener("click", function () {
runAll();
});
setTimeout(function () {
btn.remove();
}, 10000);
btn.setAttribute(attributeKey, true);
}
}
function btnClick(tt = false) {
const toggleButton = getNav();
if (!toggleButton) {
if (!tt) return;
else {
setTimeout(function () {
btnClick(tt);
}, 1000);
return;
}
}
if (!toggleButton.hasAttribute(attributeKey)) {
toggleButton.addEventListener("click", function () {
setTimeout(function () {
runAll();
btnClick();
}, 1000);
});
toggleButton.setAttribute(attributeKey, true);
} else {
if (tt) {
setTimeout(function () {
btnClick(tt);
}, 1000);
}
}
}
function checkForm() {
var elementForm = document.querySelectorAll("form");
if (!elementForm || elementForm.length === 0) {
setTimeout(function () {
checkObserver();
}, 1000);
return;
}
const cache = getCache(cacheKey);
elementForm.forEach(function (element) {
if (element.className.indexOf("xl:max-w-3xl") > -1) {
setStyle(cache, element);
}
});
}
function checkObserver() {
var parentElement = document.getElementsByClassName(targetClass)[0];
if (!parentElement) {
setTimeout(function () {
checkObserver();
}, 1000);
return;
}
const cache = getCache(cacheKey);
parentElement.querySelectorAll(targetClassName).forEach(function (flexDiv) {
setStyle(cache, flexDiv);
});
var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (!document.contains(parentElement)) {
observer.disconnect();
return;
}
mutation.addedNodes.forEach(function (addedNode) {
if (addedNode instanceof Document || addedNode instanceof Element) {
var flexDivList = addedNode.querySelectorAll(targetClassName);
flexDivList.forEach(function (flexDiv) {
setStyle(cache, flexDiv);
});
}
});
});
});
var config = { childList: true, subtree: true };
observer.observe(document.body, config);
// observer.observe(parentElement, config);
}
function runAll() {
btnClickAdd();
}
function run() {
checkForm();
checkObserver();
}
window.addEventListener("resize", runAll);
window.onload = function () {
if (window.innerWidth < desiredMinWidth) {
return;
}
checkCache();
bodyClassFunc();
styleCreate();
showTip();
btnClick();
setTimeout(function () {
runAll();
}, 2000);
};
})();